<?php

/**
 * 后台菜单管理model操作
 * @author  xiaobai
 * @date    2017-01-08
 */

namespace app\common\model;

use app\common\model\Common;
use util\Tree;
use util\Trees;

class Menu extends Common
{
    
    protected $pk      = 'id';
    const DISPLAY_SHOW = 1;     // 显示
    const DISPLAY_HIDE = 0;     // 隐藏

    protected function initialize()
    {
        parent::initialize();
        Menu::afterWrite(function ($menu) {
            $this->set_menu_find_cache($menu);
        });
    }

    public static $displays = [
        self::DISPLAY_SHOW => '显示',
        self::DISPLAY_HIDE => '隐藏',
    ];

    /**
     * 菜单添加
     * @param $data         [添加数据]
     * @return bool|mixed
     */
    public function insertMenu($data)
    {
        // 验证当前方法是否已经存在
        $where = array('module'=>$data['module'], 'control'=>$data['control'], 'action'=>$data['action']);
        $find  = $this->where($where)->column($this->pk);
        if ($find) {
            $this->error = '该操作方法已经存在';
            return false;
        }

        $res = $this->save($data);
        if ($res !== false) {
            return $this->id;
        } else {
            return false;
        }
    }

    /**
     * 更新菜单
     * @param $data         [需要更新的数据]
     * @return bool|mixed
     */
    public function updateMenu($data)
    {
        // 验证当前方法是否已经存在
        $where = [
            ['module', '=', $data['module']],
            ['control', '=', $data['control']],
            ['action', '=', $data['action']],
            ['id', '<>', $data['id']],
        ];
        $find = $this->where($where)->column($this->pk);
        if ($find) {
            $this->error = '该操作方法已经存在';
            return false;
        }

        $res = $this->where(['id'=>$data['id']])->update($data);
        if ($res !== false) {
            return $data['id'];
        } else {
            return false;
        }
    }

    /**
     * 下拉菜单，树形
     * @param int $parentid     父pid
     * @param string $order     排序
     * @return string|array
     */
    public function selectMenu($parentid = 0, $order = 'sort asc, id asc')
    {
        $result = $this->order($order)->select();
        if (empty($result)) {
            return [];
        }
        $result   = $result->toArray();
        $tree     = new Trees($result, 'parentid');
        $res_data = $tree->get_tree($parentid);

        return $res_data;
    }

    public function listMenu($where = null, $order = 'sort asc, id asc')
    {
        $result = $this->where($where)->order($order)->select();
        if (!empty($result)) {
            $result = $result->toArray();
        } else {
            $result = [];
        }

        return $result;
    }

    /**
     * 获取菜单列表，用于左侧菜单
     * @param int $type     返回类型：1左侧使用tree树形，0直接返回
     * @return array
     */
    public function menu_list_cache($type = 1)
    {
        $menu_list = cache('menu_list_cache');
        if (empty($menu_list)) {
            $menu_list = $this->listMenu();
            cache('menu_list_cache', $menu_list);
        }
        if (!empty($type)) $menu_list = get_tree($menu_list, 0);
        $menu_lists = array();
        if (!empty($menu_list)) {
            foreach ($menu_list as $k=>$v) {
                $menu_lists[$v['id']] = $v;
            }
        }

        return $menu_lists;
    }

    /**
     * 单个菜单信息写入缓存
     * @param $menu [菜单数据]
     */
    public function set_menu_find_cache($menu)
    {
        if (!empty($menu['module']) && !empty($menu['control']) && !empty($menu['action'])) {
            $menu = tp_object_array($menu);
            $key  = $menu['module'].'/'.$menu['control'].'/'.$menu['action'];
            cache($key, $menu);
        }
    }

    /**
     * 获取单个菜单缓存
     * @param $module   [模块名称]
     * @param $control  [控制器名称]
     * @param $action   [操作名称]
     * @return array|bool|false|mixed|\PDOStatement|string|\think\Model
     */
    public function get_menu_find_cache($module, $control, $action)
    {
        $key  = $module.'/'.$control.'/'.$action;
        $find = cache($key);
        if (!$find) {
            $where = array('module'=>$module, 'control'=>$control, 'action'=>$action);
            $find  = $this->where($where)->find();
            $find  = tp_object_array($find);
            cache($key, $find);
        }
        return $find;
    }

    /**
     * 获取当前操作方法的父级信息和当前栏目信息
     * @param $module       [模块名称]
     * @param $control      [控制器名称]
     * @param $action       [操作名称]
     * @return array
     */
    public function menu_parents($module, $control, $action){
        $menus      = $this->menu_list_cache(0);
        $menu_row   = $this->get_menu_find_cache($module, $control, $action);
        $res        = $this->get_tree_parent($menus, $menu_row['id'], 2);

        $res['names']   = array_reverse($res['names']);
        $res['ids'][]   = $menu_row['id'];
        $res['names'][] = array(
            'id'    => $menu_row['id'],
            'name'  => $menu_row['name'],
            'url'   => Url("{$menu_row['module']}/{$menu_row['control']}/{$menu_row['action']}{$menu_row['data']}"),
        );
        $res['row'] = $menu_row;

        return $res;
    }

    /**
     * 获取所有子集id
     * @param $data     [数据集]
     * @param $fid      [父id值]
     * @return array
     */
    public function get_tree_child($data, $fid)
    {
        $result = array();
        $fids = array($fid);
        do {
            $cids = array();
            $flag = false;
            foreach($fids as $fid) {
                for($i = count($data) - 1; $i >=0 ; $i--) {
                    $node = $data[$i];
                    if($node['fid'] == $fid) {
                        array_splice($data, $i , 1);
                        $result[] = $node['id'];
                        $cids[] = $node['id'];
                        $flag = true;
                    }
                }
            }
            $fids = $cids;
        } while($flag === true);
        return $result;
    }

    /**
     * 获取所有父级信息，默认的id集,以result里的ids为参数
     * @param $data         [数据集]
     * @param $id           [id]
     * @param int $type     [类型1是id集，2为name和URL]
     * @return array
     */
    public function get_tree_parent($data, $id, $type=1)
    {
        $result = array();
        $obj = array();
        foreach ($data as $node) {
            $obj[$node['id']] = $node;
        }
        $ids   = array();
        $names = array();

        $value = isset($obj[$id]) ? $obj[$id] : null;
        while ($value) {
            $id = null;
            foreach ($data as $node) {
                if ($node['id'] == $value['parentid']) {
                    $id = $node['id'];
                    $ids[] = $node['id'];
                    if ($type == 2) {
                        $info['id'] = $node['id'];
                        $info['name'] = $node['name'];
                        $info['url'] = Url("{$node['module']}/{$node['control']}/{$node['action']}{$node['data']}");
                        $names[$id] = $info;
                    }
                    break;
                }
            }
            if ($id === null && $type == 1) {
                $ids[] = $value['parentid'];
            }
            $value = isset($obj[$id]) ? $obj[$id] : null;
        }
        $result = array('ids'=>$ids, 'names'=>$names);
        unset($obj);
        return $result;
    }

    /**
     * 判断一个菜单是否有权限
     * @param $module
     * @param $control
     * @param $action
     * @return bool
     */
    public function is_menu_authority($module, $control, $action)
    {
        $find = $this->get_menu_find_cache($module, $control, $action);
        if (!empty($find)) {
            $menu_lists = $this->menu_list_cache(0);
            if (!empty($menu_lists[$find['id']])) {
                return true;
            }
            return false;
        }
        return false;
    }

}
